/**
 * Copyright 2010 - YangJiandong(chunquedong)
 * 
 * This file is part of ChunMap project
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE(Version >=3)
 * 
 * ChunMap是开源软件。你可以自由复制、传播本项目的下载包文件，但必须保持其完整性。
 * 我们不用对使用中的风险及由此造成的损失承担任何责任。
 * 详细情况请见《ChunMap许可协议》。
 * 
 * 想了解更多有关ChunMap的信息，请访问http://code.google.com/p/chunmap/
 * 
 * 下面此段程序作者YangJianDong(chunquedong)
 * 最后修改时间2010.7.17
 */
package chunmap.model.algorithm;


import java.util.Arrays;

import chunmap.model.coord.Position;
import chunmap.model.elem.Line;
import chunmap.model.elem.LineSegment;
import chunmap.util.MyAssert;

public class LineSegmentAlgorithm {
	/// <summary>
    /// return IPoint[]/IPoint/null
    /// </summary>
    /// <param name="me"></param>
    /// <param name="other"></param>
    /// <returns></returns>
    public static Object intersection(LineSegment me , LineSegment other)
    {
        if (!me.hasIntersect(other))
        {
            return null;
        }
        // 共线
        if (me.toVector().get2DCrossProduct(other.toVector()) == 0)
            return joinLinePart(me, other);

        // 转化为直线
        Line line1 = me.toLine();
        Line line2 = other.toLine();

        // 边缘检测，这样精度高
        if (me.onBorder(other.getEndPoint()))
        {
            return other.getEndPoint();
        }
        else if (me.onBorder(other.getStartPoint()))
        {
            return other.getStartPoint();
        }
        else if (other.onBorder(me.getEndPoint()))
        {
            return me.getEndPoint();
        }
        else if (other.onBorder(me.getStartPoint()))
        {
            return me.getStartPoint();
        }

        // 计算交点
        Position px = line1.crossPoint(line2);

        // 断言
        if (px == null) { MyAssert.unreachableCode(); }

        //检查是否合法
        if (!me.getEnvelop().contain(px) || !other.getEnvelop().contain(px))
        {
            Position[] ps = { me.getStartPoint(), me.getEndPoint(),
				other.getStartPoint(), other.getEndPoint() };
            px = getNearPoint(px, ps);
        }
        return px;
    }

    private static Position getNearPoint(Position p, Position[] ps)
    {
        int k = 0;
        double d = Double.MAX_VALUE;
        for (int i = 0, n = ps.length; i < n; i++)
        {
            LineSegment ls = new LineSegment(p, ps[i]);
            double dd = ls.getDistance();
            if (dd < d)
            {
                d = dd;
                k = i;
            }
        }

        return ps[k];
    }

    //------------------------------------------------------------------------

    /**
     * 两条线共线时计算公共部分
     * 
     * @param other
     * @return
     */
    private static Object joinLinePart(LineSegment me , LineSegment other)
    {
        Position[] points = new Position[4];
        points[0] = me.getStartPoint();
        points[1] = me.getEndPoint();
        points[2] = other.getStartPoint();
        points[3] = other.getEndPoint();

        Arrays.sort(points);// 排序

        
        if (points[1].equals(points[2]))
        {
            return points[1];
        }

        Position[] pointList = new Position[2];
        pointList[0] = points[1];
        pointList[1] = points[2];

        return pointList;
    }
}
